/*****************************************************************************
 * $LastChangedDate: 2011-04-23 21:07:07 -0400 (Sat, 23 Apr 2011) $
 * @file
 * @author  Jim E. Brooks  http://www.palomino3d.org
 * @brief   Various small functions: function macros, inline functions, template functions.
 * @remarks Include this before types.hh.
 *          Writing "inline" in template functions does increase speed (gcc 3.4).
 *          Omitted (mostly) functions for C++ arrays to encourage use of STL containers or Array.
 *          Write double-braces {{ }} in multi-statement macros
 *          to catch mis-expanding them in if/else clauses.
 *//*
 * LEGAL:   COPYRIGHT (C) 2004 JIM E. BROOKS
 *          THIS SOURCE CODE IS RELEASED UNDER THE TERMS
 *          OF THE GNU GENERAL PUBLIC LICENSE VERSION 2 (GPL 2).
 *****************************************************************************/

#ifndef DOXYGEN  // doxygen can't parse this correctly
#ifndef BASE_FUNCS_HH
#define BASE_FUNCS_HH 1

#include <cstdlib>  // std::abs(int)
#include <cmath>    // std::abs(fp)

namespace base {

////////////////////////////////////////////////////////////////////////////////
//////////////////////////  function macros  ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*******************************************************************************
 * Min()/Max() is strongly recommended and faster if either arg is a computation,
 * but requires both args to be the same type.
 * Macro MIN()/MAX() lets the compiler automatically convert args of different types,
 * but be warned: has the well-known side-effect of compiling each arg twice!
 *******************************************************************************/
template<typename T> inline T Min( T a, T b ) { return (a < b) ? a : b; }
template<typename T> inline T Max( T a, T b ) { return (a > b) ? a : b; }
#ifndef MIN
#define MIN(A,B) ( ((A) < (B)) ? (A) : (B) )
#endif
#ifndef MAX
#define MAX(A,B) ( ((A) > (B)) ? (A) : (B) )
#endif

/*******************************************************************************
 * std::abs() is defined in <cstdlib> and <cmath> (int and fp).
 *******************************************************************************/
#define ABS(X) std::abs((X))

/*******************************************************************************
 * DEPRECATED.
 *******************************************************************************/
#ifndef STREQ
#define STREQ(A,B) ( ((A) != NULL) and ((B) != NULL) and strcmp((A),(B)) == 0 )
#endif
#ifndef STRNE
#define STRNE(A,B) ( ((A) != NULL) and ((B) != NULL) and strcmp((A),(B)) != 0 )
#endif
#ifndef STREMPTY
#define STREMPTY(S) ( ((S) == NULL) or ((S)[0] == '\0') )
#endif
#ifndef STRSTR
#define STRSTR(A,B) ( ((A) != NULL) and ((B) != NULL) and (strstr((A),(B)) != NULL) )
#endif
#ifndef MEMEQ
#define MEMEQ(S1,S2,LEN) ( memcmp((S1),(S2),(LEN)) == 0 )
#endif
#ifndef MENNE
#define MEMNE(S1,S2,LEN) ( memcmp((S1),(S2),(LEN)) != 0 )
#endif
#define ELEMS(ARRAY) (uint( sizeof((ARRAY)) / sizeof((ARRAY)[0]) ))  // DEPRECATED

/*******************************************************************************
 * Bit functions.
 *******************************************************************************/
#define IF_BIT(VAR,BIT)    (((VAR) & (BIT)) != 0)
#define CLEAR_BIT(VAR,BIT) ((VAR) &= (~(BIT)))
#define SET_BIT(VAR,BIT)   ((VAR) |= (BIT))

/*******************************************************************************
 * Nullifying a pointer after deleting can avoid memory corruption.
 *******************************************************************************/
#define DELETE_NULL( OBJ ) delete (OBJ), (OBJ) = NULL

////////////////////////////////////////////////////////////////////////////////
////////////////////////////  inline functions  ////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*******************************************************************************
 * Clear memory.
 *******************************************************************************/
INLINE void CLEAR( void* p, uint n )
{
    memset( p, 0, n );
}

/*******************************************************************************
 * Force a value negative.  Opposite of absolute.
 *******************************************************************************/
INLINE int         NEG( int         x ) { return (x < 0) ? x : -x; }
INLINE long int    NEG( long int    x ) { return (x < 0) ? x : -x; }
INLINE float       NEG( float       x ) { return (x < 0) ? x : -x; }
INLINE double      NEG( double      x ) { return (x < 0) ? x : -x; }
INLINE long double NEG( long double x ) { return (x < 0) ? x : -x; }

////////////////////////////////////////////////////////////////////////////////
/////////////////////////  template functions  /////////////////////////////////
////////////////////////////////////////////////////////////////////////////////

/*****************************************************************************
 * Swap.
 *****************************************************************************/
template<typename T> inline void Swap( T& a, T& b )
{
    const T a2 = a;
    a = b;
    b = a2;
}

} // namespace base

#endif // BASE_FUNCS_HH
#endif // DOXYGEN
